/**
 * @file acl.c
 *
 * Copyright (C) Huawei Technologies Co., Ltd. 2023. All Rights Reserved.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */
#include <string.h>
#include "acl/acl.h"
#include "log_inner.h"
#include "runtime/rt.h"
#include "framework/executor_c/ge_executor.h"
#include "mmpa_api.h"
#include "ref_obj.h"

#if defined(__cplusplus)
extern "C" {
#endif
static RefObj gInitRefCount;

static inline bool PathIsLegal(const char *cfg) {
  mmFileHandle *fd = mmOpenFile(cfg, FILE_READ);
  if (fd == NULL) {
    return false;
  }
  (void)mmSeekFile(fd, 0, MM_SEEK_FILE_END);
  bool isLegal = mmTellFile(fd) == 0 ? false : true;
  mmCloseFile(fd);
  return isLegal;
}

static void *InitHookFunc(RefObj *obj, const void *userData) {
  const rtError_t rtErr = rtInit();
  if (rtErr != RT_ERROR_NONE) {
    ACL_LOG_INNER_ERROR("rt init fail, ret = %d", rtErr);
    return NULL;
  }
  Status ret = GeInitialize();
  if (ret != SUCCESS) {
    ACL_LOG_INNER_ERROR("ge init fail, ret = %d", ret);
    rtDeinit();
    return NULL;
  }
  const char *configPath = (const char *)userData;
  if (PathIsLegal(configPath)) {
    ret = GeDbgInit(configPath);
    if (ret != SUCCESS) {
      (void)GeFinalize();
      rtDeinit();
      return NULL;
    }
  }
  return obj;
}

aclError aclInit(const char *configPath) {
  if (GetObjRefWithUserData(&gInitRefCount, configPath, InitHookFunc) == NULL) {
    ACL_LOG_ERROR("Add refCount err");
    return ACL_ERROR_INTERNAL_ERROR;
  }
  ACL_LOG_INFO("Increased refCount: %lu", (uint64_t)gInitRefCount.refCount);
  return ACL_SUCCESS;
}

static void DeinitHookFunc(RefObj *obj) {
  (void)obj;
  (void)GeDbgDeInit();
  (void)GeFinalize();
  rtDeinit();
}
aclError aclFinalize() {
  ReleaseObjRef(&gInitRefCount, DeinitHookFunc);
  ACL_LOG_INFO("Decreased refCount: %lu", (uint64_t)gInitRefCount.refCount);
  return ACL_SUCCESS;
}

aclError aclrtGetVersion(int32_t *majorVersion, int32_t *minorVersion,
                         int32_t *patchVersion) {
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(majorVersion);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(minorVersion);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(patchVersion);
  // Acl version is (*majorVersion).(*minorVersion).(*patchVersion)
  *majorVersion = ACL_MAJOR_VERSION;
  *minorVersion = ACL_MINOR_VERSION;
  *patchVersion = ACL_PATCH_VERSION;
  ACL_LOG_INFO("acl version is %d.%d.%d", *majorVersion, *minorVersion,
               *patchVersion);

  return ACL_SUCCESS;
}

const char *aclGetRecentErrMsg() {
  return GetErrorMessage();
}

#if defined(__cplusplus)
}
#endif